package main

import (
	"fmt"
	"reflect"
)

// CreateReturnPtr 创建并返回指针
func CreateReturnPtr(name string, age int) interface{} {
	// 获取Person类型的反射类型对象
	personType := reflect.TypeOf(Person{})
	// 使用TypeOf创建一个指向Person类型的指针的反射值对象
	personPtrType := reflect.PointerTo(personType)
	// 使用New创建一个指向Person类型的零值的指针
	pVal := reflect.New(personPtrType.Elem()) // 这里使用personPtrType.Elem()是因为我们实际上需要的是指向Person类型的指针的指针，但因为我们用的是PtrTo，所以这里实际上是多余的。修正为：personPtr := reflect.New(personType)
	//获取真实的结构体值
	tValue := pVal.Elem()
	// 通过反射值设置字段值
	tValue.FieldByName("Name").SetString(name)
	tValue.FieldByName("Age").SetInt(int64(age))
	// 返回指向Person的指针的接口{}类型（实际上是*Person）
	return pVal.Interface()
}

func ReflectOnStructPtr(ptr interface{}) {

	if !IsPointerToStruct(ptr) {
		panic("ptr is not pointer to struct")
	}

	value := reflect.ValueOf(ptr) // ptr 是指向结构体的指针

	/**
	反射的Value需要通过Elem方法获取到指针指向的实际值（如果它是指针的话），并且需要确保这个值是可寻址的（addressable），即可以被赋值。
	*/
	elemValue := value.Elem() // 获取指针指向的值
	if !elemValue.CanAddr() {
		panic("Element is not addressable")
	}

	field := elemValue.FieldByName("Name") // 通过字段名获取字段的Value对象
	if field.IsValid() && field.CanSet() { // 检查字段是否有效且可设置
		field.SetString("New Name") // 设置新的字符串值
	} else {
		fmt.Println("Field not found or cannot be set")
	}
}

// IsPointerToStruct 判断变量是否是指向结构体的指针
func IsPointerToStruct(v interface{}) bool {
	// 获取变量的反射类型对象
	t := reflect.TypeOf(v)
	// 检查变量是否是指针类型
	if t.Kind() != reflect.Ptr {
		return false
	}
	// 获取指针指向的元素类型
	elemType := t.Elem()
	// 检查元素类型是否为结构体类型
	return elemType.Kind() == reflect.Struct
}
